home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!tektronix!tekgen!tekred!games
- From: games@tekred.CNA.TEK.COM
- Newsgroups: comp.sources.games
- Subject: v06i044: bj1 - blackjack game (first version)
- Message-ID: <3808@tekred.CNA.TEK.COM>
- Date: 6 Apr 89 00:15:11 GMT
- Sender: billr@tekred.CNA.TEK.COM
- Lines: 851
- Approved: billr@saab.CNA.TEK.COM
-
- Submitted-by: srt@aerospace.aero.org
- Posting-number: Volume 6, Issue 44
- Archive-name: bj1
-
- [Once again, two implementations arrive within days of each other.
- They both have their advantages, so I'm posting both of them. This
- one has a cute curses interface that draws little cards and prompts
- you with the proper move when it thinks you've made a bad decision.
- The second version has configuration files for the rules specific to
- several Las Vegas casinos and also has a makefile for Unix and MS-DOS. -br]
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 1 (of 1)."
- # Contents: README Makefile blackjack.c
- # Wrapped by billr@saab on Wed Apr 5 17:07:10 1989
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(606 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- XMuch as I hate to write a Blackjack program, there don't seem to be any
- Xreally good ones available. Hence this program.
- X
- XThis version allows:
- X
- X(1) Hit, Stand, Double Down, Splitting
- X(2) Advice (Basic Strategy)
- X
- XAs distributed, this program plays a 2 deck game using Las Vegas
- Xdowntown rules (hit soft 17). These parameters can be easily
- Xmodified.
- X
- XYou can hit (h), stand, (space), double down (d), or split (s).
- X
- XThere is currently no differential betting or count.
- X
- XThe program will beep and advise you of incorrect plays according
- Xto the basic blackjack strategy.
- X
- XScott R. Turner (srt@cs.ucla.edu).
- END_OF_FILE
- if test 606 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(130 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X# Makefile for Blackjack
- X
- Xbj: blackjack.c
- X cc -O -o bj blackjack.c -lcurses -ltermcap
- X
- Xinstall: bj
- X strip bj; mv bj /usr/games/bj
- END_OF_FILE
- if test 130 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'blackjack.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'blackjack.c'\"
- else
- echo shar: Extracting \"'blackjack.c'\" \(14933 characters\)
- sed "s/^X//" >'blackjack.c' <<'END_OF_FILE'
- X/*
- X * Blackjack
- X * Copyright (C) 1988 Scott R. Turner (srt@cs.ucla.edu).
- X *
- X * ----------------------------------------------------------------------
- X * LICENSE AGREEMENT
- X *
- X * You may copy and distribute copies or portions of this program
- X * as you receive it, in any medium, provided that you conspicuously and
- X * appropriately publish on each copy a valid copyright notice "Copyright
- X * (C) 1988 Scott R. Turner" (or with whatever year is appropriate) and keep
- X * intact the notices on all files that refer to this License Agreement.
- X * You may not charge a fee for distribution or copying of this
- X * program or any program which contains this program in whole or part.
- X * ----------------------------------------------------------------------
- X *
- X * Author's Notes
- X *
- X * Much as I hate to write a Blackjack program, there don't seem to be any
- X * really good ones available. Hence this program.
- X *
- X * This version allows:
- X *
- X * (1) Hit, Stand, Double Down, Splitting
- X * (2) Advice (Basic Strategy)
- X *
- X * As distributed, this program plays a 2 deck game using Las Vegas
- X * downtown rules (hit soft 17). These parameters can be easily
- X * modified.
- X *
- X * You can hit (h), stand, (space), double down (d), or split (s).
- X *
- X * There is currently no differential betting or count.
- X *
- X * The program will beep and advise you of incorrect plays according
- X * to the basic blackjack strategy.
- X *
- X * Program Notes
- X *
- X * To change the dealer rules, see the play_dealer routine.
- X *
- X * To change the # of decks (to a maximum of 4), change the value
- X * of numcards in main to the appropriate number. To play more than
- X * 4 decks you'll also have to change some declarations.
- X *
- X * Cards are represented as integers from 1-52. N mod 13 gives the
- X * rank of the card. N mod 4 gives the suit.
- X *
- X * Cards are shuffled by exchange. The number of exchanges is set
- X * in NUMEXCHANGE. Currently 2000.
- X *
- X * Note various timing "delay"s in the code; these can be modified to
- X * suit your own machine. LONGSLEEP and SHORTSLEEP for Unix-y.
- X *
- X * Correct_play encapsulates the "basic strategy" and determines whether
- X * the player's action was correct.
- X */
- X#include <ctype.h>
- X#include <stdio.h>
- X#include <curses.h>
- X
- X#define NUMEXCHANGE 2000
- X#define MESSAGES 7
- X#define STATUS 8
- X#define DEALER 3
- X#define DEALERLINE 2
- X#define PLINE1 10
- X#define PLINE2 18
- X#define LONGSLEEP 20000
- X#define SHORTSLEEP 5000
- X
- Xint cards[209]; /* Maximum # of cards in 4 decks. */
- Xint numcards; /* Number of cards (decks * 52) */
- Xint top; /* Top card in the deck. */
- Xint player[2][21]; /* 21 is the maximum # of cards in a hand. */
- Xint dealer[21];
- Xint pnum[2],
- X dnum; /* Number actually in the hand. */
- Xint ptot[2], dtot; /* Totals (?) */
- Xint bet[2];
- Xint money;
- Xint ddown[2];
- Xint stand[2];
- Xint split; /* Split flag. */
- Xint quit;
- Xchar suitc[]={0,'C','D','H','S'}; /* Suits */
- X
- X/* Session Statistics */
- X
- Xint numhands, numbust, numbj, nummp;
- X
- X/*
- X * init_hand initializes all the global variables
- X * pertinent to the beginning of a new hand.
- X *
- X */
- X
- Xvoid init_hand()
- X{
- X pnum[0] = pnum[1] = dnum = 0;
- X ptot[0] = ptot[1] = dtot = 0;
- X bet[0] = bet[1] = 2;
- X ddown[0] = ddown[1] = 0;
- X stand[0] = stand[1] = 0;
- X split = 0;
- X};
- X
- X/*
- X * Shuffle initializes the deck and shuffles it up.
- X *
- X */
- X
- Xvoid shuffle()
- X{
- X int i,j,tmp;
- X
- X for(i=1;i<=numcards;i++)
- X cards[i] = i;
- X top = 1;
- X
- X /*
- X * Exchange.
- X *
- X */
- X for(i=0;i<=NUMEXCHANGE;i++) {
- X#ifdef TURBOC
- X j = random(numcards)+1;
- X#else
- X j = (random()%numcards)+1;
- X#endif
- X tmp = cards[j];
- X cards[j] = cards[1];
- X cards[1] = tmp;
- X };
- X
- X};
- X
- X/*
- X * Rank returns the rank of a card.
- X *
- X */
- X
- Xint rank(i)
- X int i;
- X{
- X return((i % 13) + 1);
- X};
- X
- X/*
- X * value returns the value of a hand closest
- X * to 21.
- X *
- X */
- X
- Xint value(h,s)
- X int *h,s;
- X{
- X int tot, aces, i, r;
- X
- X tot = aces = 0;
- X
- X for(i=0;i<s;i++) {
- X r = rank(h[i]);
- X if (r == 1) aces++;
- X if (r > 10) r = 10;
- X tot += r;
- X };
- X
- X while (tot < 12 && aces) {
- X aces--;
- X tot += 10;
- X };
- X
- X return(tot);
- X};
- X
- X/*
- X * Bust is similar to value, except it returns 0/1 for bust.
- X *
- X */
- X
- Xint bust(h,s)
- X int *h,s;
- X{
- X int tot, i, r;
- X
- X tot = 0;
- X
- X for(i=0;i<s;i++) {
- X r = rank(h[i]);
- X if (r > 10) r = 10;
- X tot += r;
- X };
- X
- X if (tot > 21) return(1);
- X else return(0);
- X
- X};
- X
- X/*
- X * My front end to getc.
- X *
- X */
- X
- Xchar mgetc(allowed)
- X char *allowed;
- X{
- X char c;
- X
- X do {
- X c = getch();
- X if (islower(c)) c = toupper(c);
- X if (c == 'Q') {
- X clear();
- X move(10,0);
- X printw("Session Statistics");
- X move(12,0);
- X printw(" Hands played: %d.",numhands-1);
- X move(13,0);
- X printw(" Hands misplayed: %d.", nummp);
- X move(14,0);
- X printw(" Hands busted: %d.",numbust);
- X move(15,0);
- X printw(" Blackjacks: %d.",numbj);
- X move(16,0);
- X printw(" Winnings: $%d.",money);
- X move(20,0);
- X refresh();
- X nocrmode();
- X /**
- X quit = 1;
- X break;
- X **/
- X exit(1);
- X };
- X } while (!strchr(allowed,c));
- X return(c);
- X
- X};
- X
- X/*
- X * determine_results figures out what happened with
- X * the bets.
- X *
- X */
- X
- Xvoid determine_results()
- X{
- X int i;
- X
- X for(i=0;i<=split;i++) {
- X move(MESSAGES,0);
- X clrtoeol();
- X /* First, if you bust, you lose. */
- X if (bust(player[i],pnum[i])) {
- X printw("Bust! You lose $%d.",bet[i]);
- X money -= bet[i];
- X } else if (bust(dealer,dnum)) {
- X printw("Dealer busts. You win $%d.",bet[i]);
- X money += bet[i];
- X } else if (value(dealer,dnum) == value(player[i],pnum[i])) {
- X printw("Push.");
- X } else if (value(dealer,dnum) > value(player[i],pnum[i])) {
- X printw("Dealer has %d. You lose $%d.",value(dealer,dnum),bet[i]);
- X money -= bet[i];
- X } else {
- X printw("Dealer had %d. You win $%d.",value(dealer,dnum),bet[i]);
- X money += bet[i];
- X };
- X move(STATUS,0);
- X clrtoeol();
- X printw("Stake $%d",money);
- X refresh();
- X#ifdef TURBOC
- X delay(1500);
- X#else
- X usleep(LONGSLEEP);
- X#endif
- X };
- X};
- X
- X/*
- X * display_card prints the card on the screen.
- X *
- X */
- X
- Xvoid display_card(hand,num,line)
- X int *hand, num, line;
- X{
- X int r,suit,start,tot;
- X
- X r = (hand[num-1] % 13) + 1;
- X if (r<1 || r>13) {
- X move(MESSAGES,0);
- X printw("Weird value: %d.\n",r);
- X refresh();
- X mgetc(" ");
- X };
- X suit = (hand[num-1] - 1 / 13)%4;
- X start = 5 * (num - 1);
- X move(line, start);
- X printw("+----+");
- X move(line + 1,start);
- X printw("| |");
- X move(line + 2,start);
- X printw("| |");
- X move(line + 3,start);
- X printw("+----+");
- X
- X if (line == DEALERLINE && num == 1) {
- X /* Special - hide this card. */
- X move(line+1,start+1);
- X printw("####");
- X move(line+2,start+1);
- X printw("####");
- X return;
- X };
- X
- X move(line + 1,start+1);
- X switch(r) {
- X case 1: printw("A"); break;
- X case 10: printw("10"); break;
- X case 11: printw("J"); break;
- X case 12: printw("Q"); break;
- X case 13: printw("K"); break;
- X default: printw("%d",r); break;
- X };
- X
- X printw("%c",suitc[suit+1]);
- X};
- X
- X/*
- X * Deal deals a card to the indicated hand or player,
- X * also displaying it on the screen at the appropriate
- X * spot.
- X */
- X
- Xvoid deal(who)
- X int who;
- X{
- X if (who == DEALER) {
- X dealer[dnum++] = cards[top++];
- X dtot = value(dealer,dnum);
- X display_card(dealer,dnum,DEALERLINE);
- X } else {
- X player[who][pnum[who]++] = cards[top++];
- X ptot[who] = value(player[who],pnum[who]);
- X if (!who) {
- X display_card(player[who],pnum[who],PLINE1);
- X move(PLINE1+2,(5*pnum[who]+2));
- X printw("(%d)",ptot[who]);
- X } else {
- X display_card(player[who],pnum[who],PLINE2);
- X move(PLINE2+2,(5*pnum[who]+2));
- X printw("(%d)",ptot[who]);
- X };
- X };
- X refresh();
- X#ifdef TURBOC
- X delay(100);
- X#else
- X usleep(SHORTSLEEP);
- X#endif
- X};
- X
- X/*
- X * play_dealer plays the dealers hand according to the
- X * standard rules.
- X *
- X * Downtown (hit soft 17) rules.
- X */
- X
- Xvoid play_dealer()
- X{
- X while (dtot < 17 || (dtot == 17 && soft(dealer,dnum))) {
- X deal(DEALER);
- X };
- X};
- X
- X/*
- X * Reveal the dealer's card.
- X *
- X */
- X
- Xvoid reveal()
- X{
- X int r,suit,start,line;
- X
- X r = (dealer[0] % 13) + 1;
- X suit = (dealer[0] - 1 / 13)%4;
- X start = 0;
- X line = DEALERLINE;
- X /* Special - unhide this card. */
- X move(line+1,start+1);
- X printw(" ");
- X move(line+2,start+1);
- X printw(" ");
- X move(line + 1,start+1);
- X switch(r) {
- X case 1: printw("A"); break;
- X case 10: printw("10"); break;
- X case 11: printw("J"); break;
- X case 12: printw("Q"); break;
- X case 13: printw("K"); break;
- X default: printw("%d",r); break;
- X };
- X
- X printw("%c",suitc[suit+1]);
- X refresh();
- X};
- X
- X/*
- X * True if a hand is "soft".
- X *
- X */
- X
- Xint soft(h,s)
- X int *h,s;
- X{
- X int tot, aces, i, r;
- X
- X tot = aces = 0;
- X
- X for(i=0;i<s;i++) {
- X r = rank(h[i]);
- X if (r == 1) aces++;
- X if (r > 10) r = 10;
- X tot += r;
- X };
- X
- X if (aces && tot < 12) return(1);
- X return(0);
- X};
- X
- Xchar correct_play(h,z)
- X int *h,z;
- X{
- X int s,t,u,r;
- X
- X s = soft(h,z);
- X t = value(h,z);
- X u = rank(dealer[1]);
- X if (u > 10) u = 10;
- X
- X if (t < 9) return('H');
- X
- X /*
- X * Splitting.
- X *
- X */
- X
- X if (rank(h[0]) == rank(h[1]) && z == 2) {
- X r = rank(h[0]);
- X if (r == 1 || r == 8 || (r == 9 && u != 7 && u != 10 && u != 1) ||
- X (r == 7 && u < 8) || (r == 6 && u < 7 && u > 2) ||
- X (r == 2 && u > 3 && u < 8) ||
- X (r == 3 && u > 3 && u < 8)) {
- X return('S');
- X };
- X };
- X
- X /*
- X * Doubling
- X *
- X */
- X
- X /* Soft */
- X if (s && z == 2 &&
- X (((t == 18 || t == 17) && u > 2 && u < 7) ||
- X ((t == 16 || t == 15) && u > 3 && u < 7) ||
- X ((t == 14 || t == 13) && u > 4 && u < 7))) {
- X return('D');
- X }
- X /* Hard */
- X if (!s && z == 2 &&
- X (t == 11 && u != 1) ||
- X (t == 10 && u != 1 && u != 10) ||
- X (t == 9 && u > 2 && u < 7)) {
- X return('D');
- X }
- X
- X /*
- X * Hit or Stand.
- X *
- X */
- X
- X if (!s) {
- X /* Hard hand. */
- X if (t > 16) {
- X return(' ');
- X } else if (t == 12 && (u == 2 || u == 3)) {
- X return('H');
- X } else if (u < 7 && u != 1) {
- X return(' ');
- X } return('H');
- X } else {
- X /* Soft hand. */
- X if (t < 18) {
- X return('H');
- X } else if (t == 18 && (u > 8 || u == 1)) {
- X return('H');
- X } else return(' ');
- X };
- X};
- X
- X
- X
- Xmain()
- X{
- X /*
- X * Logic
- X *
- X * (1) Shuffle if necessary.
- X * (2) Initialize players.
- X * (3) Deal two cards to each player.
- X * (a) blackjack check.
- X * (4) Enter play loop.
- X * For each hand:
- X * (a) ask player what to do.
- X * (b) do it, if legal.
- X * (c) check for bust.
- X * (5) Play dealer's hand.
- X * (6) Determine results.
- X * (7) Repeat
- X *
- X */
- X
- X int i;
- X char c,correct;
- X
- X#ifdef TURBOC
- X randomize();
- X#else
- X srandom((int) time(0));
- X#endif
- X quit = 0;
- X numhands = 0;
- X numbust = 0;
- X numbj = 0;
- X nummp = 0;
- X
- X /*
- X * Curses initialization.
- X *
- X */
- X initscr();
- X crmode();
- X noecho();
- X move(0,20);
- X printw("*B*L*A*C*K*J*A*C*K*");
- X top = 300;
- X numcards = 104; /* 2 deck game */
- X
- X while(!quit) {
- X
- X /* Shuffle check. */
- X if (top >= (numcards * .60)) {
- X move(MESSAGES,0);
- X clrtoeol();
- X printw("Shuffling... ");
- X refresh();
- X#ifdef TURBOC
- X delay(250);
- X#else
- X usleep(SHORTSLEEP);
- X#endif
- X shuffle();
- X };
- X
- X /* Initialize. */
- X
- X init_hand();
- X
- X /* Clear appropriate parts of the screen. */
- X for(i=0;i<=4;i++) {
- X move(DEALERLINE+i,0);
- X clrtoeol();
- X move(PLINE1+i,0);
- X clrtoeol();
- X move(PLINE2+i,0);
- X clrtoeol();
- X move(STATUS,0);
- X clrtoeol();
- X move(STATUS+1,0);
- X clrtoeol();
- X };
- X
- X /* Deal two cards to each. */
- X
- X deal(DEALER);
- X deal(DEALER);
- X deal(0);
- X deal(0);
- X numhands++;
- X
- X /* Blackjacks? */
- X
- X if (dtot == 21 && ptot[0] == 21) {
- X reveal();
- X move(MESSAGES,0);
- X clrtoeol();
- X printw("Double Blackjack! Push.");
- X refresh();
- X#ifdef TURBOC
- X delay(1000);
- X#else
- X usleep(LONGSLEEP);
- X#endif
- X continue;
- X } else if (dtot == 21) {
- X reveal();
- X move(MESSAGES,0);
- X clrtoeol();
- X printw("Dealer Blackjack! You lose $%d.",bet[0]);
- X money -= bet[0];
- X move(STATUS,0);
- X clrtoeol();
- X printw("Stake $%d",money);
- X refresh();
- X#ifdef TURBOC
- X delay(1000);
- X#else
- X usleep(LONGSLEEP);
- X#endif
- X continue;
- X } else if (ptot[0] == 21) {
- X reveal();
- X move(MESSAGES,0);
- X clrtoeol();
- X printw("Blackjack! You win $%d.",(bet[0]*1.5));
- X money += bet[0]*1.5;
- X move(STATUS,0);
- X clrtoeol();
- X printw("Stake $%d",money);
- X refresh();
- X#ifdef TURBOC
- X delay(1000);
- X#else
- X usleep(LONGSLEEP);
- X#endif
- X numbj++;
- X continue;
- X };
- X
- X /* Play loop. */
- X
- X while (!stand[0] || (split && !stand[1])) {
- X
- X again:
- X
- X for(i=0;i<=split;i++)
- X if (!stand[i]) {
- X
- X /* Go to the proper spot. */
- X
- X if (i == 0) move(PLINE1+2,(5*pnum[0]+6));
- X else move(PLINE2+2,(5*pnum[1]+6));
- X refresh();
- X
- X /* Ask him what to do. */
- X c = mgetc(" HSD");
- X correct = correct_play(player[i],pnum[i]);
- X
- X /* Beep to annoy him. */
- X if (c != correct) {
- X#ifdef TURBOC
- X sound(75);
- X delay(100);
- X sound(35);
- X delay(50);
- X nosound();
- X#else
- X#endif
- X move(STATUS+1,0);
- X printw("Correct play was '%c'.",correct);
- X refresh();
- X nummp++;
- X };
- X
- X /* Do it. */
- X switch(c) {
- X case 'Q':
- X /* quit */
- X break;
- X
- X case ' ':
- X /* Stand. */
- X stand[i] = 1;
- X break;
- X
- X case 'H':
- X /* Hit. */
- X deal(i);
- X break;
- X
- X case 'S':
- X /* Split. */
- X if (!split && pnum[0] == 2 &&
- X rank(player[0][0]) == rank(player[0][1])) {
- X split = 1;
- X player[1][0] = player[0][1];
- X pnum[0] = 1;
- X display_card(player[0],1,PLINE1);
- X deal(0);
- X display_card(player[1],1,PLINE2);
- X pnum[1] = 1;
- X deal(1);
- X /* Only one card after splitting aces. */
- X if (rank(player[0][0]) == 1) {
- X stand[0] = 1;
- X stand[1] = 1;
- X };
- X goto again;
- X };
- X break;
- X
- X case 'D':
- X /* Double Down. */
- X if (pnum[i] == 2) {
- X bet[i] *= 2;
- X deal(i);
- X stand[i] = 1;
- X };
- X break;
- X
- X };
- X
- X /* Bust check. */
- X
- X if (bust(player[i],pnum[i])) {
- X move(MESSAGES,0);
- X clrtoeol();
- X printw("Bust!");
- X stand[i] = 1;
- X refresh();
- X numbust++;
- X };
- X };
- X };
- X
- X /* Play dealers hand. */
- X
- X reveal();
- X play_dealer();
- X
- X
- X /* Determine Results. */
- X
- X determine_results();
- X
- X };
- X
- X};
- END_OF_FILE
- if test 14933 -ne `wc -c <'blackjack.c'`; then
- echo shar: \"'blackjack.c'\" unpacked with wrong size!
- fi
- # end of 'blackjack.c'
- fi
- echo shar: End of archive 1 \(of 1\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have the archive.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-